package tt.dz.service.imp.platform2platform;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import tt.dz.service.platform2platform.TeldPlatFormService;
import tt.dz.util.HttpUtil;

@Component
public class TeldPlatFormServiceImpl implements TeldPlatFormService {
	private static Logger log = LoggerFactory.getLogger(TeldPlatFormServiceImpl.class);
	
	/** 特来电分配给电桩的商户号 */
	private String client_id = "teldvobcsodsb31bxrsm";
	/** 特来电分配给电桩的Secret */
	private String client_secret = "OrnOH36fSW";
	/** 特来电分配给电桩的key */
	private String key = "bPsX6df8Ey9OFm6BnySbIr/S1f7ptgtD";
	/** DES加密密钥加密 */
	private String desKey = "6ICQng69";
	/** Des初始向量 */
	//private String desIV = "VmzykHqJ9FzOqMGLHmEaOpLddqkeUngw";
	private String desIV = "VmzykHqJ";
	
	/** 上次获取token的时间 */
	private AtomicLong lastGetTokenTime = new AtomicLong(0l);
	
	/** 超时时间的毫秒数 */
	private final long TIMEOUT_HOURS = 1000 * 60 * 60 * 24;
	
	/** 获取token的重试次数 */
	private final int getTokenRetryCount = 3;
	
	public static JSONArray stationInfoListCache = new JSONArray();
	
	private String access_token = null;
	
	private String getTokenUrl = "http://open.teld.cn/OAuth/Token";
	
	private String getStationInfoListUrl = "http://open.teld.cn/api/Sta/PostSta";
	
	private String getStationDetailUrl = "http://open.teld.cn/api/Sta/PostStaDetail";
	
	private String getPileDetailUrl = "http://open.teld.cn/api/Sta/PostPileDetail";
	
	private final String INPUT_CHARSET = "utf-8";

	public TeldPlatFormServiceImpl() {
		
	}
	
//	@PostConstruct
	public void init(){
		try {
			refreshStationInfoList();
		} catch (Exception e) {
			log.error("初始化获取特来电站点信息发生异常", e);
		}
	}

	/**
	 * 除去数组中的空值和签名参数
	 * @param sArray 签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	@SuppressWarnings("unused")
	private Map<String, String> paraFilter(JSONObject sArray) {
		Map<String, String> result = new HashMap<String, String>();
		if (sArray == null || sArray.size() <= 0) {
			return result;
		}
		for (String key : sArray.keySet()) {
			String value = (String) sArray.get(key);
			if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
					|| key.equalsIgnoreCase("sign_type")) {
				// 值为空或者key为"sign"的参数不进行拼接
				continue;
			}
			result.put(key, value);
		}
		return result;
	}
	
	/**
	 * 验证sign签名
	 */
	@SuppressWarnings("unused")
	private boolean verify(JSONObject params, String sign) throws NoSuchAlgorithmException, UnsupportedEncodingException{
		/*
		//过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = paraFilter(params);
    	//拼接字符串
        String linkedStr = createLinkString(sParaNew);
        */
		String preSignStr = new StringBuilder("requestMsg=").append(params.toJSONString()).append(key).toString();
        String signedStr = DigestUtils.md5Hex(preSignStr.getBytes(INPUT_CHARSET)).toLowerCase();
        return sign.equals(signedStr);
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * @param params 需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	@SuppressWarnings("unused")
	private String createLinkString(Map<String, String> params) {
		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);
		StringBuilder prestr = new StringBuilder();
		int keySize = keys.size();
		for (int i = 0; i < keySize; i++) {
			String key = keys.get(i);
			String value = params.get(key);
			prestr.append(key).append("=").append(value).append("&");
		}
		prestr.deleteCharAt(prestr.length() - 1);
		return prestr.toString();
	}
	
	/**
	 * 微信支付生成sign签名
	 * @return 签名字符串
	 */
	private String sign(JSONObject params) throws UnsupportedEncodingException {
		/*
		//过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = paraFilter(params);
    	//拼接字符串
        String linkedStr = createLinkString(sParaNew);
        */
        String preSignStr = new StringBuilder("requestMsg=").append(params.toJSONString()).append(key).toString();
        String signedStr = DigestUtils.md5Hex(preSignStr.getBytes(INPUT_CHARSET)).toLowerCase();
        return signedStr;
	}
	
	/**
	 * 加密
	 * @param message 待加密的字符串
	 * @return 加密后的字符串
	 */
	public String encrypt(String message) {
		byte[] bytes = null;
		try {
			DESKeySpec desKeySpec = new DESKeySpec(desKey.getBytes());
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
			IvParameterSpec iv = new IvParameterSpec(desIV.getBytes());
			Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
			bytes = cipher.doFinal(message.getBytes());
		} catch (Exception e) {
			log.error("", e);
		}
		return new String(new BASE64Encoder().encode(bytes));
	}
	
	/**
	 * 解密
	 * @param message 待解密的字符串
	 * @return 解密后的字符串
	 * @throws UnsupportedEncodingException 
	 */
	public String decrypt(String encryptMsg) throws UnsupportedEncodingException {
		byte[] bytes = null;
		try {
			DESKeySpec desKeySpec = new DESKeySpec(desKey.getBytes());
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
			IvParameterSpec iv = new IvParameterSpec(desIV.getBytes());
			Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
			bytes = cipher.doFinal(new BASE64Decoder().decodeBuffer(encryptMsg));
		} catch (Exception e) {
			log.error("", e);
		}
		return new String(bytes, INPUT_CHARSET);
	}
	
	/**
	 * 判断上次获取Token到现在是否超过1.5小时
	 */
	private boolean isTokenTimeout(){
		long now = Calendar.getInstance().getTimeInMillis();
		if(now - lastGetTokenTime.get() >= TIMEOUT_HOURS){
			return true;
		}
		return false;
	}
	
	/**
	 * 发送请求，获取Token
	 */
	private void doGetToken(int count) throws Exception {
		if(count == 0){
			access_token = null;
			throw new Exception("重试" + getTokenRetryCount + "次获取Token失败");
		}
		Map<String, String> headerMap = new HashMap<String, String>();
		headerMap.put("Content-Type", "application/json; charset=utf-8");
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("grant_type", "client_credentials");
		paramMap.put("client_id", client_id);
		paramMap.put("client_secret", client_secret);
		String resultStr = HttpUtil.postRequest(getTokenUrl, headerMap, paramMap);
		if(resultStr == null){
			doGetToken(count - 1);
		}
		JSONObject jsonResult = JSON.parseObject(resultStr);
		String retToken = jsonResult.getString("access_token");
		if(retToken == null){
			doGetToken(count - 1);
		} else {
			access_token = retToken;
		}
	}

	/**
	 * 获取Token
	 */
	private void getToken() throws Exception {
		doGetToken(getTokenRetryCount);
	}
	
	private JSONObject callAPI(String url, JSONObject jsonReqMsg) throws Exception{
		if(access_token == null){
			getToken();
		}
		Map<String, String> headerMap = new HashMap<String, String>();
		headerMap.put("Authorization", "Bearer" + " " + access_token);
		headerMap.put("Content-Type", "application/json; charset=utf-8");
		JSONObject jsonParam = new JSONObject();
		jsonParam.put("sign", sign(jsonReqMsg));
        String encryptedReq = encrypt(jsonReqMsg.toJSONString());
		jsonParam.put("requestMsg", encryptedReq);
		String resultStr = HttpUtil.postRequest(url, headerMap, jsonParam.toJSONString());
		if(resultStr == null){
			throw new Exception("向特来电的http接口发送请求返回为null");
		}
		JSONObject retJSON = JSON.parseObject(resultStr);
		String resultCode = retJSON.getString("resultCode");
		if(resultCode == null || !resultCode.equals("0")){
			log.error("向特来电的http接口发送请求，resultCode:" + resultCode);
			throw new Exception("向特来电的http接口发送请求出错，resultCode:" + resultCode);
		}
		String resultValue = retJSON.getString("resultValue");
		if(resultValue == null){
			throw new Exception("向特来电的http接口发送请求出错，resultValue为空");
		}
		resultValue = decrypt(resultValue);
		JSONObject jsonResult = JSON.parseObject(resultValue);
		/* 不验证sign
		String sign = retJSON.getString("sign");
		if(!verify(jsonResult, sign)){
			log.error("向特来电的http接口发送请求，验证sign签名失败：" + resultStr);
			throw new Exception("向特来电的http接口发送请求，验证sign签名失败，resultStr:" + resultStr);
		}
		*/
		return jsonResult;
	}
	
	private void refreshStationInfoList() throws Exception{
		if(access_token == null){
			getToken();
		}
		JSONObject jsonReqMsg = new JSONObject();
		//jsonReqMsg.put("opState", "运营中");
		jsonReqMsg.put("pageNo", "1");
		jsonReqMsg.put("pageSize", "100");
		JSONObject jsonResultValue = callAPI(getStationInfoListUrl, jsonReqMsg);
		//得到总页数
		Integer pageCount = jsonResultValue.getInteger("pageCount");
		if(pageCount == null || pageCount <= 0){
			log.error("向特来电获取电站信息列表返回总页数出错，pageCount：" + pageCount);
			throw new Exception("向特来电获取电站信息列表返回总页数出错，pageCount：" + pageCount);
		}
		JSONArray staList = jsonResultValue.getJSONArray("staList");
		if(staList != null && staList.size() > 0){
			stationInfoListCache.clear();
			stationInfoListCache.addAll(staList);
		}
		if(pageCount > 1){
			for(int i = 2; i <= pageCount.intValue(); i++){
				jsonReqMsg.put("pageNo", i + "");
				JSONObject jsonResultValueTmp = callAPI(getStationInfoListUrl, jsonReqMsg);
				JSONArray staListTmp = jsonResultValueTmp.getJSONArray("staList");
				if(staListTmp != null && staListTmp.size() > 0){
					stationInfoListCache.addAll(staListTmp);
				}
			}
		}
	}

	
	private JSONObject refreshPageStationInfoList(String pageNo,String pageSize) throws Exception{
		if(access_token == null){
			getToken();
		}
		JSONObject jsonReqMsg = new JSONObject();
		//jsonReqMsg.put("opState", "运营中");
		jsonReqMsg.put("pageNo", pageNo);
		jsonReqMsg.put("pageSize", pageSize);
		JSONObject jsonResultValue = callAPI(getStationInfoListUrl, jsonReqMsg);
		//得到总页数
		Integer pageCount = jsonResultValue.getInteger("pageCount");
		if(pageCount == null || pageCount <= 0){
			log.error("向特来电获取电站信息列表返回总页数出错，pageCount：" + pageCount);
			throw new Exception("向特来电获取电站信息列表返回总页数出错，pageCount：" + pageCount);
		}
		JSONArray staList = jsonResultValue.getJSONArray("staList");
		if(staList != null && staList.size() > 0){
			JSONObject jSONObject = new JSONObject();
			jSONObject.put("pageCount", pageCount);
			jSONObject.put("staList", staList);
			return  jSONObject;
		}else
		{
			return null;
		}
		
		
	}
	
	@Override
	public JSONArray getStationInfoList() throws Exception{
		if(access_token == null || isTokenTimeout()){
			long currentValue = lastGetTokenTime.get();
			if(lastGetTokenTime.compareAndSet(currentValue, Calendar.getInstance().getTimeInMillis())){
				getToken();
				refreshStationInfoList();
			}
		}
		return stationInfoListCache;
	}

//	@Override
//	public JSONObject getPageStationInfoList(String pageNo,String pageSize) throws Exception{
//		long currentValue = lastGetTokenTime.get();
//		if(lastGetTokenTime.compareAndSet(currentValue, Calendar.getInstance().getTimeInMillis())){
//			getToken();
//			return refreshPageStationInfoList(pageNo,pageSize);
//		}else {
//			return null;
//		}
//		
//	}
	
	
	@Override
	public JSONObject getPageStationInfoList(String pageNo,String pageSize) throws Exception{
		if(access_token == null || isTokenTimeout()){
			long currentValue = lastGetTokenTime.get();
			if(lastGetTokenTime.compareAndSet(currentValue, Calendar.getInstance().getTimeInMillis())){
				getToken();
				refreshStationInfoList();
			}
		}
		int ipageNo = Integer.parseInt(pageNo);
		int ipageSize = Integer.parseInt(pageSize);
		int endIndex = ipageNo*ipageSize;
		if (endIndex>stationInfoListCache.size()) {
			endIndex = stationInfoListCache.size();
		}
		JSONObject jSONObject = new JSONObject();
		jSONObject.put("pageCount", stationInfoListCache.size());
		jSONObject.put("staList", stationInfoListCache.subList((ipageNo-1)*ipageSize, endIndex));
		return  jSONObject;
	}
	
	@Override
	public JSONObject getStationDetail(String staCode) throws Exception{
		if(access_token == null || isTokenTimeout()){
			long currentValue = lastGetTokenTime.get();
			if(lastGetTokenTime.compareAndSet(currentValue, Calendar.getInstance().getTimeInMillis())){
				getToken();
			}
		}
		JSONObject jsonReqMsg = new JSONObject();
		jsonReqMsg.put("staCode", staCode);
		JSONObject jsonResultValue = callAPI(getStationDetailUrl, jsonReqMsg);
		return jsonResultValue;
	}

	@Override
	public JSONObject getPileDetail(String pileCode) throws Exception{
		if(access_token == null || isTokenTimeout()){
			long currentValue = lastGetTokenTime.get();
			if(lastGetTokenTime.compareAndSet(currentValue, Calendar.getInstance().getTimeInMillis())){
				getToken();
			}
		}
		JSONObject jsonReqMsg = new JSONObject();
		jsonReqMsg.put("pileCode", pileCode);
		JSONObject jsonResultValue = callAPI(getPileDetailUrl, jsonReqMsg);
		return jsonResultValue;
	}
	
	public static void main(String[] args) throws Exception{
		TeldPlatFormServiceImpl t = new TeldPlatFormServiceImpl();
		t.getStationInfoList();
	}
}
